package com.patternity.dotgraph;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.util.Properties;

/**
 * Java wrapper around dot grapher; requires Graphviz to be installed on the
 * machine.
 * 
 * @author cyrille martraire
 */
public final class DotRenderer {

	private final String path;

	private final String dotPath;

	private final String commandTemplate;

	public final static Properties loadProperties(final File file) {
		try {
			final Properties properties = new Properties();
			properties.load(new FileInputStream(file));
			System.out.println("Loaded properties: " + properties.size()
					+ " values");
			return properties;
		} catch (final IOException e) {
			System.err.println("Could not find configuration file: "
					+ file.getAbsolutePath());
			return null;
		}
	}

	/**
	 * Constructor from the config properties
	 */
	public DotRenderer(final Properties prop) {
		this(prop.getProperty("outpath"), prop.getProperty("dotpath"), prop
				.getProperty("commandline"));
	}

	public DotRenderer(final String path, final String dotPath,
			final Properties prop) {
		this(path, dotPath, prop.getProperty("commandline"));
	}

	/**
	 * @param path
	 *            The path to dot and png files, must end with a slash
	 * @param dotPath
	 *            The path to the dot executable, must end with a slash
	 * @param cmd
	 *            The command-line template, e.g.
	 *            "$0 dot -Tpng $1.dot -o $1.png -Gdpi=72 -Gsize="6,8.5""
	 */
	public DotRenderer(final String path, final String dotPath, final String cmd) {
		this.path = path;
		this.dotPath = dotPath;
		commandTemplate = cmd;
	}

	public String getCommandTemplate() {
		return commandTemplate;
	}

	public String getDotPath() {
		return dotPath;
	}

	public String getPath() {
		return path;
	}

	/**
	 * @param filename
	 *            The filename without the extension and its path
	 * 
	 *            Run dot: dot -Tpng filename.dot -o filename.png
	 */
	public void render(final String filename) {
		try {
			final Object[] args = { dotPath, path + filename };
			final String command = MessageFormat.format(commandTemplate, args);
			System.out.println(command);

			final Process p = Runtime.getRuntime().exec(command);
			final BufferedReader reader = new BufferedReader(
					new InputStreamReader(p.getErrorStream()));

			String line = null;
			while ((line = reader.readLine()) != null) {
				System.out.println(line);
			}
			final int result = p.waitFor();
			if (result != 0) {
				System.err.println("Errors running Graphviz on " + filename
						+ ".dot");
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @param filename
	 *            The filename without the extension and its path
	 * 
	 *            Writes as path + filename.dot
	 */
	public void write(final String filename, final String content) {
		try {
			final String outputFileName = path + filename + ".dot";
			final String outputEncoding = "ISO-8859-1";
			final FileOutputStream fos = new FileOutputStream(outputFileName);
			final PrintWriter w = new PrintWriter(new BufferedWriter(
					new OutputStreamWriter(fos, outputEncoding)));

			System.out.println("Writing file " + outputFileName + "...");
			w.println(content);

			w.flush();
		} catch (final FileNotFoundException e) {
			e.printStackTrace();
		} catch (final UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * All-in-on convenience method
	 * 
	 * @return The filename of the dot-generated picture for the given content
	 */
	public String toImage(final String filename, final String content) {
		write(filename, content);
		render(filename);
		return filename + ".png";
	}

	@Override
	public String toString() {
		return "DotPrinter path=" + path + " dot-path=" + dotPath;
	}
}
